/*
 * Time : 2023/3/11 14:01
 * Auth : weixinlong
 * Email : weixinlong@buaa.edu.cn
 * File : mission.go
 */

package handler

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/cloudwego/hertz/pkg/app"
	"github.com/cloudwego/hertz/pkg/common/hlog"
	"github.com/cloudwego/hertz/pkg/common/utils"
	"gorm.io/gorm"
	"hertz/demo/biz/model"
	"hertz/demo/biz/mw"
	"hertz/demo/biz/util"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type MissionRet struct {
	// ID
	ID        uint      `gorm:"primaryKey;not null" json:"id"`
	CreatedAt time.Time `json:"created_at,omitempty"`
	UpdatedAt time.Time `json:"updated_at,omitempty"`

	// 任务名称
	Name string `gorm:"unique;not null" json:"name"`

	// 需要标注的内容
	Label json.RawMessage `gorm:"not null" json:"label"`

	// 任务所属的用户id
	AuthorID uint `gorm:"not null" json:"author_id"`

	// 注释
	Comment string `json:"comment"`
}

func GetInterfaceToString(value interface{}) string {
	// interface 转 string
	var key string
	if value == nil {
		return key
	}

	switch value.(type) {
	case float64:
		ft := value.(float64)
		key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
		ft := value.(float32)
		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
		it := value.(int)
		key = strconv.Itoa(it)
	case uint:
		it := value.(uint)
		key = strconv.Itoa(int(it))
	case int8:
		it := value.(int8)
		key = strconv.Itoa(int(it))
	case uint8:
		it := value.(uint8)
		key = strconv.Itoa(int(it))
	case int16:
		it := value.(int16)
		key = strconv.Itoa(int(it))
	case uint16:
		it := value.(uint16)
		key = strconv.Itoa(int(it))
	case int32:
		it := value.(int32)
		key = strconv.Itoa(int(it))
	case uint32:
		it := value.(uint32)
		key = strconv.Itoa(int(it))
	case int64:
		it := value.(int64)
		key = strconv.FormatInt(it, 10)
	case uint64:
		it := value.(uint64)
		key = strconv.FormatUint(it, 10)
	case string:
		key = value.(string)
	case time.Time:
		t, _ := value.(time.Time)
		key = t.String()
		// 2022-11-23 11:29:07 +0800 CST  这类格式把尾巴去掉
		key = strings.Replace(key, " +0800 CST", "", 1)
		key = strings.Replace(key, " +0000 UTC", "", 1)
	case []byte:
		key = string(value.([]byte))
	default:
		newValue, _ := json.Marshal(value)
		key = string(newValue)
	}

	return key
}

func AddMission(ctx context.Context, c *app.RequestContext) {
	type temp struct {
		// 任务名称
		Name string `json:"name"`
		// 需要标注的内容
		Label interface{} `json:"label"`
		// 任务所属的用户id
		AuthorID uint `json:"author_id"`
		// 注释
		Comment string `json:"comment"`
	}
	var t temp
	if err := c.BindAndValidate(&t); err != nil {
		util.BadRequest(c, err)
		return
	}
	value := model.Mission{
		Name:     t.Name,
		Label:    GetInterfaceToString(t.Label),
		AuthorID: t.AuthorID,
		Comment:  t.Comment,
	}

	if err := model.AddMission(mw.GetDB(c), &value); err != nil {
		hlog.CtxErrorf(ctx, "AddJob db error: %w", err)
		util.ErrMessage(c, http.StatusInternalServerError, "db error")
		return
	}
	c.JSON(http.StatusOK, utils.H{"id": value.ID})
}

func DeleteMissionById(ctx context.Context, c *app.RequestContext) {
	id, err := util.GetParamUint(c, "id")
	if err != nil {
		util.BadRequest(c, err)
	}

	user := mw.GetUser(c)
	if user == nil {
		util.ErrMessage(c, http.StatusUnauthorized, "unauthorized")
		return
	}

	if err := model.DeleteMission(mw.GetDB(c), uint(id), user.Admin, uint(user.Id)); err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.NotFound()
			return
		}

		hlog.CtxErrorf(ctx, "DeleteMission db error: %w", err)
		util.ErrMessage(c, http.StatusInternalServerError, "db error")
		return
	}

	c.Status(http.StatusOK)

}

func ListMission(ctx context.Context, c *app.RequestContext) {

	ret := []model.Mission{}
	builder := mw.GetDB(c)
	err := builder.Find(&ret).Error
	if err != nil {
		hlog.CtxErrorf(ctx, "GetLabel db error: %w", err)
		return
	}
	res := []MissionRet{}
	for _, value := range ret {
		label := json.RawMessage(value.Label)
		temp := MissionRet{
			ID:        value.ID,
			CreatedAt: value.CreatedAt,
			UpdatedAt: value.UpdatedAt,
			Name:      value.Name,
			Label:     label,
			AuthorID:  value.AuthorID,
			Comment:   value.Comment,
		}
		res = append(res, temp)
	}

	c.JSON(http.StatusOK, res)
}

func FindMissionByID(ctx context.Context, c *app.RequestContext) {
	id, err := util.GetParamUint(c, "id")
	if err != nil {
		util.BadRequest(c, err)
		return
	}

	db := mw.GetDB(c)
	ret, err := model.FindMissionByID(db, uint(id))
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.NotFound()
		} else {
			hlog.CtxErrorf(ctx, "ListMission db error: %w", err)
			util.ErrMessage(c, http.StatusInternalServerError, "db error")
		}
		return
	}
	// label, err := json.Marshal(ret.Label)
	label := json.RawMessage(ret.Label)
	res := MissionRet{
		ID:        ret.ID,
		CreatedAt: ret.CreatedAt,
		UpdatedAt: ret.UpdatedAt,
		Name:      ret.Name,
		Label:     label,
		AuthorID:  ret.AuthorID,
		Comment:   ret.Comment,
	}

	c.JSON(http.StatusOK, res)
}

func FindMissionStatusByID(ctx context.Context, c *app.RequestContext) {
	id, err := util.GetParamUint(c, "id")
	if err != nil {
		util.BadRequest(c, err)
		return
	}

	db := mw.GetDB(c)
	var selections []model.Selection
	db.Find(&selections)
	total := len(selections)
	var finished int64 = 0
	var pending int64 = 0
	db.Model(model.Label{}).Where("status = ? and mission_id = ?", "confirmed", id).Count(&finished)
	db.Model(model.Label{}).Where("status = ? and mission_id = ?", "submit", id).Count(&pending)
	c.JSON(http.StatusOK, utils.H{"total": total,
		"confirmed": finished,
		"submit":    pending})
}

func FindMissionVideoByID(ctx context.Context, c *app.RequestContext) {
	id, err := util.GetParamUint(c, "id")
	if err != nil {
		util.BadRequest(c, err)
		return
	}

	db := mw.GetDB(c)
	type result struct {
		// DICOM视频的uid
		InstanceUid string `gorm:"not null" json:"instance_uid"`

		// 视频文件的DICOM 序列号, series number
		SeriesNumber uint `gorm:"not null" json:"series_number"`

		// 视频文件的DICOM 序列号, instance number
		InstanceNumber uint `gorm:"not null" json:"instance_number"`

		// DICOM视频文件的sha1 hash, 使用小写16进制格式
		SHA1 string `gorm:"not null" json:"sha1"`
		// 视频DICOM文件相对于DICOMDIR文件所在目录的位置
		Path string `gorm:"not null" json:"path"`
		// 视频所属的切面
		View string `gorm:"not null" json:"view"`
		// 视频相关的注释
		Comment string `json:"comment"`
		// 标注结果的审核状态
		Status string `gorm:"not null;default:working" json:"status"`
	}
	var total []result
	db.Model(&model.Selection{}).Select("media.instance_uid,media.series_number,media.instance_number,media.sha1,media.path,media.view,media.comment,labels.status").Joins("left join media on selections.id = media.selection_id").Joins("left join labels on labels.media_id = media.id").Where("mission_id = ?", id).Find(&total)
	c.JSON(http.StatusOK, utils.H{"video": total})
}
